//
//  NSMutableArray+Swizzling.m
//  RuntimeTest
//
//  Created by Charles on 16/9/27.
//  Copyright © 2016年 Charles. All rights reserved.
//

#import "NSMutableArray+Swizzling.h"
#import "NSObject+Swizzling.h"
#import <objc/runtime.h>

@implementation NSMutableArray (Swizzling)

+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self swizzleSelector:@selector(removeObject:) withSwizzledSelector:@selector(cl_safeRemoveObject:)];
        
        [objc_getClass("__NSArrayM") swizzleSelector:@selector(addObject:) withSwizzledSelector:@selector(cl_safeAddobject:)];
        
        [objc_getClass("__NSArrayM") swizzleSelector:@selector(removeObjectAtIndex:) withSwizzledSelector:@selector(cl_safeRemoveObjectAtIndex:)];
    
        [objc_getClass("__NSArrayM") swizzleSelector:@selector(insertObject:atIndex:) withSwizzledSelector:@selector(cl_insertObject:index:)];
        
        [objc_getClass("__NSPlaceholderArray") swizzleSelector:@selector(initWithObjects:count:) withSwizzledSelector:@selector(cl_initWithObjects:count:)];
        
        [objc_getClass("__NSArrayM") swizzleSelector:@selector(objectAtIndex:) withSwizzledSelector:@selector(cl_objectAtIndex:)];
        
    });
}

- (instancetype)cl_initWithObjects:(const id  _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt{
    BOOL hasNilObject = NO;
    for (NSInteger i = 0; i < cnt; i++) {
        if ([objects[i] isKindOfClass:[NSArray class]]) {
            NSLog(@"%@", objects[i]);
        }
        if (objects[i] == nil) {
            hasNilObject = YES;
            NSLog(@"%s object at index %lu is nil, it will be filtered", __FUNCTION__, i);
        }
    }
    
    //如果有值为nil的元素,那么我们可以过滤掉值为nil的元素
    if (hasNilObject) {
        id __unsafe_unretained newObjects[cnt];
        
        NSUInteger index = 0;
        for (NSUInteger i = 0; i<cnt; i++) {
            if (objects[i] != nil) {
                newObjects[index++] = objects[i];
            }
        }
        NSLog(@"%@",[NSThread callStackSymbols]);
        return [self cl_initWithObjects:newObjects count:index];
    }
    return [self cl_initWithObjects:objects count:cnt];
}

- (void)cl_safeAddobject:(id)object{
    if (object == nil) {
        NSLog(@"%s can add nil object into NSMutableArray",__FUNCTION__);
    }else{
        [self cl_safeAddobject:object];
    }
}

- (void)cl_safeRemoveObject:(id)obj{
    if (obj == nil) {
        NSLog(@"%s call -removeObjet:, but argument obj is nil",__FUNCTION__);
        return;
    }
    [self cl_safeRemoveObject:obj];
}

- (void)cl_insertObject:(id)object index:(NSInteger)index{
    if (object == nil) {
        NSLog(@"%s can't insert nil into NSMutableArray",__FUNCTION__);
    }else if (index > self.count){
        NSLog(@"%s index is invalid",__FUNCTION__);
    }else{
        [self cl_insertObject:object index:index];
    }
}

- (id)cl_objectAtIndex:(NSUInteger)index {
    if (self.count == 0) {
        NSLog(@"%s can't get any object from an empty array",__func__);
        return nil;
    }
    if (index > self.count) {
        NSLog(@"%s index out of bounds in array",__FUNCTION__);
        return nil;
    }
    return [self cl_objectAtIndex:index];
}

- (void)cl_safeRemoveObjectAtIndex:(NSUInteger)index {
    if (self.count <= 0) {
        NSLog(@"%s can't get any object from an empty array",__FUNCTION__);
        return;
    }
    if (index >= self.count) {
        NSLog(@"%s index out of bound",__FUNCTION__);
        return;
    }
    [self cl_safeRemoveObjectAtIndex:index];
}
@end
